package MWClient;

import jssc.*;

/**
 * <pre>
 * @Package : MWClient
 * @File    : SerialComm.java
 * <pre>
 *
 * @Author  : 차재우
 * @Date    : 2013. 7. 22.
 * @Version :
 */
public class SerialComm {
	private SerialPort sp = null;
	private SerialQueue recvQueue = null;

	/**
	 * <pre>
	 * @Comment : 생성자
	 * <pre>
	 *
	 * @param serialPort
	 */
	public SerialComm(String serialPort) {
		sp = new SerialPort(serialPort);
		recvQueue = MWClient.recvQueue;
		PortOpen();
	}

	/**
	 * <pre>
	 * @Comment : RS232 포트 열기 
	 * <pre>
	 *
	 * @Method  : PortOpen
	 * @Return  : void
	 */
	private void PortOpen() {
		try {
			sp.openPort();
			sp.setParams(SerialPort.BAUDRATE_115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
			int mask = SerialPort.MASK_RXCHAR + SerialPort.MASK_CTS + SerialPort.MASK_DSR;
			sp.setEventsMask(mask);
			sp.addEventListener(new SerialPortReader());
			
			Thread serialSender = new Thread(new SerialSender(sp));
			serialSender.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * <pre>
	 * @Package : MWClient
	 * @File    : SerialComm.java
	 * <pre>
	 *
	 * @Author  : 차재우
	 * @Date    : 2013. 7. 22.
	 * @Version :
	 */
	class SerialPortReader implements SerialPortEventListener {
		private boolean stxFlag = false;
		private boolean sizeFlag = false;
		private boolean dataFlag = false;
		private boolean etxFlag = false;	
		private int dataSize = 0;
		
		/**
		 * <pre>
		 * @Comment : RS232 수신 이벤트
		 * <pre>
		 *
		 * @Method  : serialEvent
		 * @Return  : void 
		 * @param event
		 */
		public void serialEvent(SerialPortEvent event) {
			if (event.isRXCHAR()) {
				if(event.getEventValue() < 2)
					return;
				if (!stxFlag) {
					FindSTX(event);
				}

				if(event.getEventValue() < 4)
					return;
				if(!sizeFlag) {
					GetDataSize(event);
				}
				
				if(event.getEventValue() < dataSize)
					return;
				if(!dataFlag) {
					RecvData(event);
				}
				
				if(event.getEventValue() < 2)
					return;
				if(!etxFlag) {
					FindETX(event);
				}

				if(stxFlag == true && sizeFlag == true && dataFlag == true && etxFlag == true)
					stxFlag = sizeFlag = dataFlag = etxFlag = false;
			} else if (event.isCTS()) {// If CTS line has changed state
				if (event.getEventValue() == 1) {// If line is ON
					System.out.println("CTS - ON");
				} else {
					System.out.println("CTS - OFF");
				}
			} else if (event.isDSR()) {// /If DSR line has changed state
				if (event.getEventValue() == 1) {// If line is ON
					System.out.println("DSR - ON");
				} else {
					System.out.println("DSR - OFF");
				}
			}
		}
		
		/**
		 * <pre>
		 * @Comment : ETX 필드를 찾는다.
		 * <pre>
		 *
		 * @Method  : FindETX
		 * @Return  : 
		 * @param event
		 */
		private void FindETX(SerialPortEvent event) {
			if(event.getEventValue() >= 2)
			{
				try {
					byte[] etx = sp.readBytes(2);
					etxFlag = true;
					System.out.println("etx find....ok");
				} catch (SerialPortException ex) {
					ex.printStackTrace();
				}
			}
		}
		
		/**
		 * <pre>
		 * @Comment : 시리얼 데이터 수신
		 * <pre>
		 *
		 * @Method  : RecvData
		 * @Return  : 
		 * @param event
		 */
		private void RecvData(SerialPortEvent event) {
			byte[] dataBuf = new byte[dataSize];
			
			if(event.getEventValue() >= dataSize)
			{
				try {
					dataBuf = sp.readBytes(dataSize);
					recvQueue.Push(dataBuf);
					dataFlag = true;
					System.out.println("data find....ok");
				} catch (SerialPortException ex) {
					ex.printStackTrace();
				}
			}
		}

		/**
		 * <pre>
		 * @Comment : Data 필드 사이즈 정보 
		 * <pre>
		 *
		 * @Method  : GetDataSize
		 * @Return  : 
		 * @param event
		 */
		private void GetDataSize(SerialPortEvent event) {
			byte[] size = null;
			
			if(event.getEventValue() >= 4)
			{
				try {
					size = sp.readBytes(4);
					dataSize = ByteUtil.toInt(size);
					sizeFlag = true;
					System.out.println("size find....ok");
				} catch (SerialPortException ex) {
					ex.printStackTrace();
				}
			}
		}

		/**
		 * <pre>
		 * @Comment : STX 필드를 찾는다. 
		 * <pre>
		 *
		 * @Method  : FindSTX
		 * @Return  : 
		 * @param event
		 */
		private void FindSTX(SerialPortEvent event)
		{
			byte[] stx = null;
			
			if(event.getEventValue() >= 2)
			{
				while (true) {
					do {
						try {
							stx = sp.readBytes(1);
						} catch (SerialPortException ex) {
							ex.printStackTrace();
						}
					} while (stx[0] != 0x01);
					
					try {
						stx = sp.readBytes(1);
						if(stx[0] == 0x01)
						{
							stxFlag = true;
							System.out.println("stx find....ok");
							break;
						}
					} catch (SerialPortException ex) {
						ex.printStackTrace();
					}
				}
			}
		}
		
		/**
		 * <pre>
		 * @Comment : byte 버퍼 출력 
		 * <pre>
		 *
		 * @Method  : DisplayBuffer
		 * @Return  : 
		 * @param buf
		 */
		private void DisplayBuffer(byte[] buf) {
			for(int i = 0 ; i < buf.length ; i++)
				System.out.print(buf[i] + " ");
			System.out.println("\n");
		}
	}
}
